package com.zhihuishu.micro.course.openapi.app.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

import com.able.openapi.zhsCourse.IOnlineSchoolForZhsCourseService;
import com.zhihuishu.micro.course.dao.CourseTeacherMapper;
import com.zhihuishu.micro.course.dto.CourseDto;
import com.zhihuishu.micro.course.log.LoggerCollectionEnum;
import com.zhihuishu.micro.course.log.MDCLoggerUtil;
import com.zhihuishu.micro.course.model.AppCourseInfo;
import com.zhihuishu.micro.course.model.CourseTeacher;
import com.zhihuishu.micro.course.model.ScoreAssessRule;
import com.zhihuishu.micro.course.openapi.app.AppCourseOpenService;
import com.zhihuishu.micro.course.openapi.app.dto.ChapterWebDto;
import com.zhihuishu.micro.course.openapi.app.dto.CourseTeacherWebDto;
import com.zhihuishu.micro.course.openapi.app.dto.CourseWebDto;
import com.zhihuishu.micro.course.openapi.app.dto.LessonVideoWebDto;
import com.zhihuishu.micro.course.openapi.app.dto.LessonWebDto;
import com.zhihuishu.micro.course.openapi.app.dto.ScoreAssessRuleWebDto;
import com.zhihuishu.micro.course.openapi.online.CourseOpenService;
import com.zhihuishu.micro.course.service.AppCourseInfoService;
import com.zhihuishu.micro.course.service.ChapterService;
import com.zhihuishu.micro.course.service.CourseClipsService;
import com.zhihuishu.micro.course.service.CourseService;
import com.zhihuishu.micro.course.service.FirstStepStatService;
import com.zhihuishu.micro.course.service.LessonService;
import com.zhihuishu.micro.course.service.LessonVideoService;
import com.zhihuishu.micro.course.service.ScoreAssessRuleService;
import com.zhihuishu.remote.ErrorCode;
import com.zhihuishu.remote.RemoteException;
import com.zhihuishu.remote.RemoteResult;
import com.zhihuishu.toolkit.helper.BeanHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper.Handler;
import com.zhihuishu.toolkit.jedis.template.JedisExecutor;

@Service("appCourseOpenService")
public class AppCourseOpenServiceImpl implements AppCourseOpenService {

    @Resource
    private JedisExecutor jedisExecutor;

    @Resource
    private CourseService courseService;

    @Resource
    private CourseClipsService courseClipsService;

    @Resource
    private AppCourseInfoService appCourseInfoService;

    @Resource
    private IOnlineSchoolForZhsCourseService onlineSchoolForZhsCourseService;

    @Resource
    private ScoreAssessRuleService scoreAssessRuleService;

    @Resource
    // XXX 暂时使用Mapper接口
    private CourseTeacherMapper courseTeacherMapper;

    @Resource
    private CourseOpenService courseOpenService;

    @Resource
    private FirstStepStatService firstStepStateService;
    @Resource
    private ChapterService chapterService;
    @Resource
    private LessonService lessonService;
    @Resource
    private LessonVideoService lessonVideoService;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public RemoteResult<Map<Long, CourseWebDto>> queryCourseInfos(final long... courseIds)
            throws RemoteException {
        RemoteResult<Map<Long, CourseWebDto>> result = new RemoteResult<Map<Long, CourseWebDto>>();
        if (ArrayUtils.isNotEmpty(courseIds)) {
            final Map<Long, CourseWebDto> data = new HashMap<Long, CourseWebDto>();
            for (long courseId : courseIds) {
                CourseDto dto = courseService.get(courseId);
                if (dto != null) {
                    CourseWebDto cwd = BeanHelper.transTo(dto, CourseWebDto.class);
                    if (dto.getVideoId() != null)
                        cwd.setVideoId(dto.getVideoId().longValue());
                    cwd.setVideoImage(dto.getMovieClipsImg());
                    // 查询课程片花
                    /*
                     * if (cwd.getLinkCourseId() != null) { CourseClipsDto clips =
                     * courseClipsService.get(cwd.getLinkCourseId()); if (clips != null) {
                     * cwd.setVideoId(clips.getVideoId()); cwd.setVideoImage(clips.getVideoImage());
                     * } }
                     */
                    data.put(courseId, cwd);
                }
            }
            result.setResult(data);
        }
        return result;
    }
    
    /**
     * 注释掉的方法：redis的Pipeline.hgetall查询数据量较大时性能很差，恢复原有实现方式
     */
   /* @Override
    public RemoteResult<Map<Long, CourseWebDto>> queryCourseInfos(final long... courseIds)
            throws RemoteException {
        RemoteResult<Map<Long, CourseWebDto>> result = new RemoteResult<Map<Long, CourseWebDto>>();
        if (ArrayUtils.isNotEmpty(courseIds)) {
        	Map<Long, CourseWebDto> data = new HashMap<Long, CourseWebDto>();
        	// 先批量查缓存
            BeanWrapper<List<Object>> redisResult = jedisExecutor.executeAndReturn(new ReturnHandler<List<Object>>() {
        		@Override
        		public List<Object> handle(Jedis jedis) {
        			Pipeline pip = jedis.pipelined();
        			for (Long courseId : courseIds) {
        				pip.hgetAll(RedisKeyHelper.courseKey(courseId));
        			}
        			return pip.syncAndReturnAll();
        		}
        	});
            // 查询结果封装
            List<Object> redisCourseDtos = redisResult.getValue();
            CourseWebDto dto = null;
            for (Object redisCourse : redisCourseDtos) {
            	@SuppressWarnings("unchecked")
        		Map<String, String> map = (Map<String, String>) redisCourse;
            	if (!CollectionUtils.isEmpty(map) && map.get("courseId") != null) {
                    dto = BeanHelper.transTo(map, CourseWebDto.class);
                    if (map.get("videoId") != null) {
                    	dto.setVideoId(Long.parseLong(map.get("videoId")));
                    }
                    dto.setVideoImage(map.get("movieClipsImg"));
                    data.put(dto.getCourseId(), dto);
                }
            }
            // 缓存中未查到则查库
            if (data.size() != courseIds.length) {
            	getCourseFromDb(data, courseIds);
            }
            result.setResult(data);
        }
        return result;
    }
    
    *//** 
	 * 缓存中无数据的课程查询数据库
	 * @author ztl
	 * @date 2017年3月31日下午1:16:38
	 * @param courseIds
	 * @param courseList
	 *//*
	private void getCourseFromDb(Map<Long, CourseWebDto> courseList, final long... courseIds) {
		List<Long> noRedisCourseIds = new ArrayList<Long>();// 缓存中无数据的课程ID集合
		for (Long courseId : courseIds) {
			boolean flag = false;// true缓存中查询到了数据   false缓存无数据
			if (courseList.containsKey(courseId)) {
				// 缓存中查出了数据
				flag = true;
			}
			if (!flag) {
				noRedisCourseIds.add(courseId);
			}
		}
		// 缓存无数据的课程查询数据库
		CourseDto dto = null;
		for (Long courseId : noRedisCourseIds) {
			if (courseId != null) {
				dto = courseService.touchCourse(courseId);
				if (dto != null) {
	            	CourseWebDto cwd = BeanHelper.transTo(dto, CourseWebDto.class);
	                if (dto.getVideoId() != null) {
	                	cwd.setVideoId(dto.getVideoId().longValue());
	                }
	                cwd.setVideoImage(dto.getMovieClipsImg());
	                courseList.put(courseId, cwd);
				}
			}
		}
	}*/
    
    @Override
    public RemoteResult<List<ChapterWebDto>> queryChapterInfos(final long courseId) throws RemoteException {
        RemoteResult<List<ChapterWebDto>> result = new RemoteResult<List<ChapterWebDto>>();
        // XXX
        // 参考com.zhihuishu.micro.course.openapi.online.impl.ChapterLessonOpenServiceImpl#queryChapterBasicInfos逻辑
        final List<ChapterWebDto> chapters = new ArrayList<ChapterWebDto>();
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // 根据课程ID，获取章列表
                Set<String> chapterIds = jedis.smembers(JedisHelper.key("cc:course", courseId, "chapters"));
                if (CollectionUtils.isEmpty(chapterIds)) {
                   chapterIds=chapterService.queryChapterIdsByCourseIdAndAddToCache(courseId);
                }
                // 根据课程ID，获取节列表
                Set<String> lessonIds = jedis.smembers(JedisHelper.key("cc:course", courseId, "lessons"));
                if (CollectionUtils.isEmpty(lessonIds)) {
                    lessonIds=lessonService.queryLessonIdsByCourseId(courseId);
                }
                // 根据课程ID，获取小节列表
                Set<String> lvIds = jedis.smembers(JedisHelper.key("cc:course", courseId, "lvs"));
                if (CollectionUtils.isEmpty(lvIds)) {
                    lvIds=lessonVideoService.queryLessonVideoIdsByCourseId(courseId);
                }
                ;
                // 使用管道获取数据
                Pipeline pip = jedis.pipelined();
                // 获取章数据
                if (!CollectionUtils.isEmpty(chapterIds))
                    for (String chapterId : chapterIds) {
                        if (chapterId == null)
                            continue;
                        pip.hmget(JedisHelper.key("cc:chapter", chapterId), "name", "rank", "limitDay",
                                "isPass", "id");
                    }
                // 获取节数据
                if (!CollectionUtils.isEmpty(lessonIds))
                    for (String lessonId : lessonIds) {
                        if (lessonId == null)
                            continue;
                        pip.hmget(JedisHelper.key("cc:lesson", lessonId), "chapterId", "name", "rank",
                                "videoId", "videoSec", "haveChildren", "knowledgeCardTotal",
                                "courseDataTotal", "id");
                    }
                // 获取小节数据
                if (!CollectionUtils.isEmpty(lvIds))
                    for (String lvId : lvIds) {
                        pip.hmget(JedisHelper.key("cc:lv", lvId), "lessonId", "name", "rank", "videoId",
                                "videoSec", "id");
                    }
                // 提取结果
                List<Object> result = pip.syncAndReturnAll();
                if (CollectionUtils.isEmpty(result))
                    return;
                List<LessonWebDto> lessons = new ArrayList<LessonWebDto>();
                List<LessonVideoWebDto> lvs = new ArrayList<LessonVideoWebDto>();
                for (int i = 0, len = result.size(); i < len; i++) {
                    Object obj = result.get(i);
                    if (i < chapterIds.size()) {
                        ChapterWebDto chapter = toChapter(obj);
                        if (chapter != null && chapter.getId() != null)
                            chapters.add(chapter);
                    } else if (i < chapterIds.size() + lessonIds.size()) {
                        LessonWebDto lesson = toLesson(obj);
                        if (lesson != null && lesson.getId() != null && lesson.getChapterId() != null)
                            lessons.add(lesson);
                    } else {
                        LessonVideoWebDto lv = toLessonVideo(obj);
                        if (lv != null && lv.getId() != null && lv.getLessonId() != null
                                && lv.getRank() != null)
                            lvs.add(lv);
                    }
                }
                if (CollectionUtils.isEmpty(chapters))
                    return;

                // 组合数据
                // 如果小节列表不为空，将小节写入到节中
                if (!CollectionUtils.isEmpty(lvs)) {
                    // 小节列表排序
                    Collections.sort(lvs, new Comparator<LessonVideoWebDto>() {
                        @Override
                        public int compare(LessonVideoWebDto o1, LessonVideoWebDto o2) {
                            if (o1 == null || o2 == null)
                                return 0;
                            return o1.getRank().compareTo(o2.getRank());
                        }
                    });
                    // 组合数据
                    for (LessonWebDto lesson : lessons) {
                        for (LessonVideoWebDto lv : lvs) {
                            if (lv.getLessonId().equals(lesson.getId())) {
                                if (lesson.getLessonVideos() == null) {
                                    lesson.setLessonVideos(new ArrayList<LessonVideoWebDto>());
                                }
                                lesson.getLessonVideos().add(lv);
                            }
                        }
                    }
                }
                // 如果节列表不为空，将节写入到章中
                if (!CollectionUtils.isEmpty(lessons)) {
                    // 小节列表排序
                    Collections.sort(lessons, new Comparator<LessonWebDto>() {
                        @Override
                        public int compare(LessonWebDto o1, LessonWebDto o2) {
                            if (o1 == null || o2 == null)
                                return 0;
                            return o1.getRank().compareTo(o2.getRank());
                        }
                    });
                    // 组合数据
                    for (ChapterWebDto cwd : chapters) {
                        for (LessonWebDto lesson : lessons) {
                            if (lesson == null || lesson.getId() == null)
                                continue;
                            if (cwd.getId().equals(lesson.getChapterId())) {
                                if (cwd.getLessons() == null)
                                    cwd.setLessons(new ArrayList<LessonWebDto>());
                                cwd.getLessons().add(lesson);
                            }
                        }
                    }
                }
            }
        });
        if (!CollectionUtils.isEmpty(chapters)) {
            Collections.sort(chapters, new Comparator<ChapterWebDto>() {

                @Override
                public int compare(ChapterWebDto o1, ChapterWebDto o2) {
                    if (o1 == null || o2 == null) {
                        return 0;
                    }
                    return o1.getRank().compareTo(o2.getRank());
                }

            });
            result.setResult(chapters);
        }

        return result;
    }

    /**
     * 从Redis获取的数据转换为小节对象：[4130, 包打听黄金荣, 2, 82418, 2116, 19859]
     * 
     * @param obj
     * @return
     */
    private LessonVideoWebDto toLessonVideo(Object obj) {
        if (obj == null)
            return null;
        @SuppressWarnings("unchecked")
        List<String> list = (List<String>) obj;
        LessonVideoWebDto lvw = new LessonVideoWebDto();
        if (list.get(0) != null)
            lvw.setLessonId(NumberUtils.toInt(list.get(0).toString()));// 节id
        if (list.get(1) != null)// 名称
            lvw.setName(list.get(1).toString());
        if (list.get(2) != null)// 顺序
            lvw.setRank(NumberUtils.toInt(list.get(2).toString()));
        if (list.get(3) != null){// 视频id
            lvw.setVideoId(NumberUtils.toLong(list.get(3).toString()));
        }else {
            lvw.setVideoId(0L);//与缓存中保持一致
        }
        if (list.get(4) != null){// 视频上传
            lvw.setVideoSec(NumberUtils.toInt(list.get(4).toString()));
        }else {
            lvw.setVideoSec(0);//与缓存中保持一致
        }
        if (list.get(5) != null)// 小节id
            lvw.setId(NumberUtils.toInt(list.get(5).toString()));
        return lvw;
    }

    /**
     * 从Redis获取的数据转换为章对象：[古代上海人事物, 1, 10, 1, 1121]
     * 
     * @param obj
     * @return
     */
    private ChapterWebDto toChapter(Object obj) {
        if (obj == null)
            return null;
        @SuppressWarnings("unchecked")
        List<String> list = (List<String>) obj;
        // 判断是否通过，未通过，则认为章不存在(不对外公布)
        if (list.get(3) == null || NumberUtils.toInt(list.get(3)) == 0)
            return null;
        ChapterWebDto cwd = new ChapterWebDto();
        if (list.get(0) != null)
            cwd.setName(list.get(0).toString());
        if (list.get(1) != null)
            cwd.setRank(NumberUtils.toInt(list.get(1).toString()));
        if (list.get(2) != null)
            cwd.setLimitDay(NumberUtils.toInt(list.get(2).toString()));
        if (list.get(4) != null)
            cwd.setId(NumberUtils.toInt(list.get(4).toString()));
        return cwd;
    }

    /**
     * 从Redis获取的数据转换为节对象：[1123, 上海建筑之花园洋房, 5, 81866, 1666, 0, null, null, 4124]
     * 
     * @param obj
     * @return
     */
    private LessonWebDto toLesson(Object obj) {
        if (obj == null)
            return null;
        @SuppressWarnings("unchecked")
        List<String> list = (List<String>) obj;
        LessonWebDto lwd = new LessonWebDto();
        if (list.get(0) != null)
            lwd.setChapterId(NumberUtils.toInt(list.get(0).toString()));
        if (list.get(1) != null)
            lwd.setName(list.get(1).toString());
        if (list.get(2) != null)
            lwd.setRank(NumberUtils.toInt(list.get(2).toString()));
        if (list.get(3) != null){
            lwd.setVideoId(NumberUtils.toLong(list.get(3).toString()));
        }else {
            lwd.setVideoId(0L);//与缓存中保持一致
        }
        if (list.get(4) != null){
            lwd.setVideoSec(NumberUtils.toInt(list.get(4).toString()));
        }else {
            lwd.setVideoSec(0);//与缓存中保持一致
        }
        if (list.get(5) != null)
            lwd.setHaveChildren(NumberUtils.toInt(list.get(5).toString()) > 0);
        if (list.get(6) != null)
            lwd.setKnowledgeCardTotal(NumberUtils.toInt(list.get(6).toString()));
        if (list.get(7) != null)
            lwd.setCourseDataTotal(NumberUtils.toInt(list.get(7).toString()));
        if (list.get(8) != null)
            lwd.setId(NumberUtils.toInt(list.get(8).toString()));
        return lwd;
    }

    @Override
    public RemoteResult<Map<Long, List<CourseTeacherWebDto>>> queryCourseTeachers(long... courseIds)
            throws RemoteException {
        RemoteResult<Map<Long, List<CourseTeacherWebDto>>> result = new RemoteResult<Map<Long, List<CourseTeacherWebDto>>>();
        if (ArrayUtils.isEmpty(courseIds))
            return result;
        Map<Long, List<CourseTeacherWebDto>> map = new HashMap<Long, List<CourseTeacherWebDto>>();
        for (long courseId : courseIds) {
            List<CourseTeacher> ctList = courseTeacherMapper.listByCourse(courseId);
            if (!CollectionUtils.isEmpty(ctList)) {
                map.put(courseId, BeanHelper.transTo(ctList, CourseTeacherWebDto.class));
            }
        }
        result.setResult(map);
        return result;
    }

    @Override
    public RemoteResult<ScoreAssessRuleWebDto> findScoreAssessRuleByCourseId(long courseId)
            throws RemoteException {
        RemoteResult<ScoreAssessRuleWebDto> result = new RemoteResult<ScoreAssessRuleWebDto>();
        try {
            ScoreAssessRuleWebDto webDto = null;
            ScoreAssessRule dto = scoreAssessRuleService.findByCourseId(courseId);
            if (dto != null) {
                webDto = new ScoreAssessRuleWebDto();
                webDto.setCourseId(dto.getCourseId());
                webDto.setTotalScore(removeZeroAndDot(String.valueOf(dto.getTotalScore())));
                webDto.setOnlineScoreShare(removeZeroAndDot(String.valueOf(dto.getOnlineScoreShare())));
                webDto.setMeetCourseScoreShare(removeZeroAndDot(String.valueOf(dto.getMeetCourseScoreShare())));
                webDto.setFinalExamScoreShare(removeZeroAndDot(String.valueOf(dto.getFinalExamScoreShare())));
                webDto.setBbsScore(removeZeroAndDot(String.valueOf(dto.getBbsScore())));
                webDto.setChapterTestScoresShare(removeZeroAndDot(String.valueOf(dto
                        .getChapterTestScoresShare())));
                webDto.setLearningProcessScoresShare(removeZeroAndDot(String.valueOf(dto
                        .getLearningProcessScoresShare())));
                webDto.setPostCount(dto.getPostCount());
                webDto.setReturnPostCount(dto.getReturnPostCount());
                webDto.setPostScore(removeZeroAndDot(String.valueOf(dto.getPostScore())));
                webDto.setReturnPostScore(removeZeroAndDot(String.valueOf(dto.getReturnPostScore())));
                webDto.setIsAddScore(dto.getIsAddScore());
                webDto.setTeacherGardScore(removeZeroAndDot(String.valueOf(dto.getTeacherGardScore())));
                webDto.setPostNum(dto.getPostNum());
                webDto.setReturnPostNum(dto.getReturnPostNum());
                result.setResult(webDto);
            }
        } catch (Exception e) {
            result.setResult(null);
            result.setSuccess(false);
            throw new RemoteException(e).setMessage("查询查询考核标准执行出错!");
        }
        return result;
    }

    /**
     * 使用java正则表达式去掉多余的.与0
     * 
     * @param by ylj
     * @return
     */
    private String removeZeroAndDot(String num) {
        if (num == null || num.equals("null"))
            return "0";
        if (num.indexOf(".") > 0) {
            num = num.replaceAll("0+?$", "");// 去掉多余的0
            num = num.replaceAll("[.]$", "");// 如最后一位是.则去掉
        }
        return num;
    }

    @Override
    public RemoteResult<CourseWebDto> create(String courseName, String schoolName, long createUser,
            String createUserName) throws RemoteException {
        RemoteResult<CourseWebDto> result = new RemoteResult<CourseWebDto>();
        // 参数检查
        if (courseName == null || schoolName == null || createUserName == null) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.ARGUMENTS_ILLEGALITY);
            return result;
        }
        // 执行创建接口
        try {
            CourseDto course = courseService.create(courseName, createUser);
            MDCLoggerUtil.saveLogger(
                    String.format("app接口创建课程,courseId=%d,courseName=%s", course.getCourseId(), courseName),
                    createUser, LoggerCollectionEnum.courseCollection);
            if (course == null || course.getCourseId() == null) {
                result.setSuccess(false);
                result.setErrorCode(1);
            } else {
                course.setSchoolName(schoolName);
                course.setCourseTeacher(createUserName);
                courseService.update(course, createUser);
                courseService.touchCourse(course.getCourseId());

                CourseWebDto cod = new CourseWebDto();
                cod.setCourseId(course.getCourseId());
                cod.setLinkCourseId(course.getLinkCourseId());
                saveAppCourseInfo(course.getCourseId(), courseName, schoolName, createUser, createUserName);
                result.setResult(cod);
                onlineSchoolForZhsCourseService.clearUserAuthorityCache(createUser);// 清除用户缓存
            }
        } catch (Exception e) {
            throw new RemoteException(e).setMessage("APP创建课程执行出错!");
        }

        return result;
    }

    @Override
    public RemoteResult<Integer> userCourseCount(long userId) throws RemoteException {
        RemoteResult<Integer> result = new RemoteResult<Integer>();

        List<CourseDto> courseList = courseService.userCourseList(userId, null);
        if (CollectionUtils.isEmpty(courseList)) {
            result.setResult(0);
        } else {
            result.setResult(courseList.size());
        }
        return result;
    }

    private void saveAppCourseInfo(Long courseId, String courseName, String schoolName, long createUser,
            String createUserName) {
        AppCourseInfo appCourseInfo = new AppCourseInfo();
        appCourseInfo.setCourseId(courseId);
        appCourseInfo.setCourseName(courseName);
        appCourseInfo.setUserId(createUser);
        appCourseInfo.setUserName(createUserName);
        appCourseInfo.setSchoolName(schoolName);
        appCourseInfo.setCreateTime(new Date());
        appCourseInfoService.save(appCourseInfo);
    }

    @Override
    public RemoteResult<Void> delCourseByCourseId(Long courseId, Long userId) throws RemoteException {
        RemoteResult<Void> result = new RemoteResult<Void>();
        // 参数检查
        if (courseId == null) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.ARGUMENTS_ILLEGALITY);
            return result;
        }
        courseService.remove(courseId, userId);
        appCourseInfoService.remove(courseId);
        onlineSchoolForZhsCourseService.clearUserAuthorityCache(userId);
        
        return result;
    }
    
    

}
